package com.alex.seo.usertype;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import javax.persistence.MappedSuperclass;

import org.hibernate.HibernateException;
import org.hibernate.annotations.TypeDef;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;

import com.thoughtworks.xstream.XStream;

@MappedSuperclass
@TypeDef(defaultForType = JsonValue.class, typeClass = JsonValueUserType.class)
public class JsonValueUserType implements UserType {

	private static final int[] SQL_TYPES = { Types.LONGVARCHAR };

	private static XStream xStream = new XStream();

	@Override
	public Object assemble(Serializable cached, Object owner) throws HibernateException {
		return deepCopy(cached);
	}

	@Override
	public Object deepCopy(Object value) throws HibernateException {
		return value;
	}

	@Override
	public Serializable disassemble(Object value) throws HibernateException {
		return xStream.toXML(value);
	}

	@Override
	public boolean equals(Object x, Object y) throws HibernateException {
		if (x == null) {
			return (y != null);
		}
		return (x.equals(y));
	}

	@Override
	public int hashCode(Object x) throws HibernateException {
		return x.hashCode();
	}

	@Override
	public boolean isMutable() {
		return false;
	}

	@Override
	public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException,
			SQLException {
		if (!rs.wasNull()) {
			return new JsonValue<Object>(xStream.fromXML(rs.getString(names[0])));
		} else {
			return null;
		}
	}

	@Override
	public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException,
			SQLException {
		if (value == null) {
			st.setNull(index, SQL_TYPES[0]);
		} else {
			JsonValue<?> jsonValue = (JsonValue<?>) value;
			st.setString(index, xStream.toXML(jsonValue.get()));
		}
	}

	@Override
	public Object replace(Object original, Object target, Object owner) throws HibernateException {
		return deepCopy(original);
	}

	@Override
	public Class<?> returnedClass() {
		return JsonValue.class;
	}

	@Override
	public int[] sqlTypes() {
		return SQL_TYPES;
	}
}
